import { Vec2 } from "./geometry";
import { Mathf } from "./mathf";

/**
 * 3X3行矩阵 -- 左乘实现变换
 * @date 2023/10/18 - 16:07:49
 *
 * @export
 * @class Mat3
 * @typedef {Mat3}
 *
 */
export class Mat3 {
  data: number[] = [1, 0, 0, 0, 1, 0, 0, 0, 1];
  get x_basis() {
    return new Vec2(this.data[0], this.data[1]);
  }
  get y_basis() {
    return new Vec2(this.data[3], this.data[4]);
  }

  static makeFromBasis(xb: Vec2, yb: Vec2) {
    let mat = new Mat3();
    mat.data[0] = xb.x;
    mat.data[1] = xb.y;
    mat.data[3] = yb.x;
    mat.data[4] = yb.y;
    return mat;
  }

  translate(x: number, y: number) {
    this.data[6] = x * this.data[0] + y * this.data[3] + this.data[6];
    this.data[7] = x * this.data[1] + y * this.data[4] + this.data[7];
    return this;
  }

  translateX(x: number) {
    return this.translate(x, 0);
  }

  translateY(y: number) {
    return this.translate(0, y);
  }

  scale(x: number, y: number) {
    this.data[0] *= x;
    this.data[1] *= x;
    this.data[2] *= x;
    this.data[3] *= y;
    this.data[4] *= y;
    this.data[5] *= y;
    return this;
  }

  scaleX(x: number) {
    return this.scale(x, 1);
  }

  scaleY(y: number) {
    return this.scale(1, y);
  }

  /**
   * 自身坐标系旋转
   * @date 2023/10/18 - 16:22:43
   *
   * @param {number} x
   * @param {number} y
   */
  rotate(deg: number) {
    let rad = Mathf.deg2Rad(deg);
    let cos = Math.cos(rad);
    let sin = Math.sin(rad);

    let m11 = cos * this.data[0] + sin * this.data[3];
    let m12 = cos * this.data[1] + sin * this.data[4];
    let m13 = cos * this.data[2] + sin * this.data[5];
    let m21 = -sin * this.data[0] + cos * this.data[3];
    let m22 = -sin * this.data[1] + cos * this.data[4];
    let m23 = -sin * this.data[2] + cos * this.data[5];
    this.data[0] = m11;
    this.data[1] = m12;
    this.data[2] = m13;
    this.data[3] = m21;
    this.data[4] = m22;
    this.data[5] = m23;
    return this;
  }

  /**
   * 转置矩阵
   * @date 2023/11/30 - 14:13:21
   */
  transpos() {
    let mat = new Mat3();
    mat.data[0] = this.data[0];
    mat.data[1] = this.data[3];
    mat.data[2] = this.data[6];
    mat.data[3] = this.data[1];
    mat.data[4] = this.data[4];
    mat.data[5] = this.data[7];
    mat.data[6] = this.data[2];
    mat.data[7] = this.data[5];
    mat.data[8] = this.data[8];
    return mat;
  }

  multiply(other: Mat3) {
    let retMat = new Mat3();
    // 第1行
    retMat.data[0] =
      this.data[0] * other.data[0] +
      this.data[1] * other.data[3] +
      this.data[2] * other.data[6];

    retMat.data[1] =
      this.data[0] * other.data[1] +
      this.data[1] * other.data[4] +
      this.data[2] * other.data[7];

    retMat.data[3] =
      this.data[0] * other.data[2] +
      this.data[1] * other.data[5] +
      this.data[2] * other.data[8];

    // 第2行
    retMat.data[3] =
      this.data[3] * other.data[0] +
      this.data[4] * other.data[3] +
      this.data[5] * other.data[6];

    retMat.data[4] =
      this.data[3] * other.data[1] +
      this.data[4] * other.data[4] +
      this.data[5] * other.data[7];

    retMat.data[5] =
      this.data[3] * other.data[2] +
      this.data[4] * other.data[5] +
      this.data[5] * other.data[8];

    // 第3行
    retMat.data[6] =
      this.data[6] * other.data[0] +
      this.data[7] * other.data[3] +
      this.data[8] * other.data[6];

    retMat.data[7] =
      this.data[6] * other.data[1] +
      this.data[7] * other.data[4] +
      this.data[8] * other.data[7];

    retMat.data[8] =
      this.data[6] * other.data[2] +
      this.data[7] * other.data[5] +
      this.data[8] * other.data[8];

    return retMat;
  }

  applyToVec(v: Vec2) {
    return this.applyTo(v.x, v.y);
  }

  applyTo(x: number, y: number) {
    return new Vec2(
      x * this.data[0] + y * this.data[3] + this.data[6],
      x * this.data[1] + y * this.data[4] + this.data[7]
    );
  }
}
